﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Debug = UnityEngine.Debug;

namespace BToolkit
{
    public class BUtils : MonoBehaviour
    {
        private static BUtils instance;
        public static BUtils Instance
        {
            get
            {
                if (!instance)
                {
                    instance = FindObjectOfType<BUtils>();
                    if (!instance)
                    {
                        GameObject go = new GameObject("BUtils");
                        DontDestroyOnLoad(go);
                        instance = go.AddComponent<BUtils>();
                    }
                }
                return instance;
            }
        }
        public static Action<Texture2D> FinishCallbackEvent = null;

        public static Vector2 ScreenUISize(Canvas canvas)
        {
            return (canvas.transform as RectTransform).sizeDelta;
        }

        //当前触碰点是否再某个UI对象上方
        public static bool IsTouchOnUI(GameObject canvas, GameObject targetUI)
        {
            PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
            pointerEventData.position = Input.mousePosition;
            GraphicRaycaster graphicRaycaster = canvas.GetComponent<GraphicRaycaster>();
            if (!graphicRaycaster)
            {
                Debug.LogError("IsTouchOnUI()方法传入的canvas参数上没有GraphicRaycaster组件");
                return false;
            }
            List<RaycastResult> results = new List<RaycastResult>();
            graphicRaycaster.Raycast(pointerEventData, results);
            for (int i = 0; i < results.Count; i++)
            {
                if (results[i].gameObject == targetUI)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 启动打印机打印图片(PrintImage.exe从Plugins目录下拷贝),打印位置和长宽输入毫米
        /// </summary>
        public static void PrintPhoto(string textureFullPath, byte[] textureBytes, int xMM, int yMM, int widthMM, int heightMM)
        {
            try
            {
                string fullPath = !string.IsNullOrEmpty(textureFullPath) ? textureFullPath.Replace("/", "\\\\") : "";
                int method = 3;// Config.Instance.PrintMethod;
                switch (method)
                {
                    case 1:
                        //需要导入Unity的LCPrinter插件,且使用.Net 4.x（已下载到U盘插件文件夹，或从CSDN下载）
                        //LCPrinter.Print.PrintTexture(textureBytes, 1, "");
                        break;
                    case 2:
                        Process.Start("mspaint.exe", fullPath);
                        break;
                    case 3:
                        string exepath = Application.dataPath.Replace("/Assets", "") + @"/Res/PrintImage.exe";
                        if (!File.Exists(exepath))
                        {
                            UnityEngine.Debug.LogError("请从BToolkit/Plugins目录拷贝PrintImage.exe文件到Application.dataPath目录下。");
                            return;
                        }
                        ProcessStartInfo info = new ProcessStartInfo(exepath);
                        int widthPX = Mathf.RoundToInt(100 * widthMM / 28.346f);
                        int heightPX = Mathf.RoundToInt(100 * heightMM / 28.346f);
                        info.Arguments = string.Format("{0},{1},{2},{3},{4}", fullPath, xMM, yMM, widthPX, heightPX);
                        info.UseShellExecute = false;
                        info.CreateNoWindow = true;
                        info.RedirectStandardOutput = true;
                        using (Process p = new Process())
                        {
                            p.StartInfo = info;
                            p.Start();
                        }
                        break;
                    case 4:
                        Process process = new Process();
                        process.StartInfo.CreateNoWindow = false;
                        process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                        process.StartInfo.UseShellExecute = true;
                        process.StartInfo.FileName = fullPath;
                        process.StartInfo.Verb = "print";
                        process.Start();
                        break;
                }
            }
            catch (Exception e)
            {
                string debug = "如果使用 Print.PrintTexture()，必须使用.Net 4.x";
                debug += "\n" + e.ToString();
                File.WriteAllText(Application.dataPath + "/log.txt", debug);
            }
        }

        /// <summary>
        /// 判断字符串是否可以转为整型
        /// </summary>
        public static bool IsInt(string value)
        {
            int result;
            return int.TryParse(value, out result);
        }
        /// <summary>
        /// 判断字符串是否可以转为浮点型
        /// </summary>
        public static bool IsFloat(string value)
        {
            float result;
            return float.TryParse(value, out result);
        }

        /// <summary>
        /// 播放Animator动画
        /// </summary>
        public static void PlayAnim(Animator animator, string clipName, float transitionDuration)
        {
            if (animator)
            {
                if (transitionDuration <= 0)
                {
                    animator.Play(clipName, 0, 0f);
                }
                else
                {
                    if (animator.GetNextAnimatorStateInfo(0).fullPathHash == 0)
                    {
                        animator.CrossFade(clipName, transitionDuration);
                    }
                    else
                    {
                        animator.Play(clipName, 0, 0f);
                    }
                }
            }
        }

        /// <summary>
        /// 获取经纬度
        /// </summary>
        /*
        public delegate void GPSDelegate(float latitude,float longitude);
        static GPSDelegate GPSCallback;
        public static void GetGPS(float desiredAccuracyInMeters,float updateDistanceInMeters,GPSDelegate Callback) {
            GPSCallback = Callback;
            Instance.StartCoroutine(StartGPS(desiredAccuracyInMeters,updateDistanceInMeters));
        }
        static IEnumerator StartGPS(float desiredAccuracyInMeters,float updateDistanceInMeters) {
            if(!Input.location.isEnabledByUser) {
                Debug.Log("isEnabledByUser value is:" + Input.location.isEnabledByUser.ToString() + " Please turn on the GPS");
                yield break;
            }
            Input.location.Start(desiredAccuracyInMeters,updateDistanceInMeters);//第一个参数设置位置精确度，比如500则可不用打开GPS，用流量即可获取到，第二个参数设置设备横向移动500米位置才会更新)
            int maxWait = 20;
            while(Input.location.status == LocationServiceStatus.Initializing && maxWait > 0) {
                yield return new WaitForSeconds(1);
                maxWait--;
            }
            if(maxWait < 1) {
                Debug.Log("Init GPS service time out");
                yield break;
            }
            if(Input.location.status == LocationServiceStatus.Failed) {
                Debug.Log("Unable to determine device location");
                yield break;
            } else {
                float latitude = Input.location.lastData.longitude;
                float longitude = Input.location.lastData.latitude;
                GPSCallback(latitude,longitude);
            }
        }
        */

        /// <summary>
        /// 手机震动
        /// </summary>
        public static void MobileVibrate()
        {
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
        Handheld.Vibrate();
#endif
        }

        /// <summary>
        /// 从SD卡里安装APK包
        /// </summary>
        public static void InstallAPK(string path)
        {
            //确保已导入InstallAPK.jar包
            AndroidJavaClass jc = new AndroidJavaClass("cn.wqb.tools.InstallAPK");
            jc.CallStatic("install", path);
        }

        /// <summary>
        /// 获取当前最上层的UGUI Canvas对象。优先选择Overlay类型的Canvas，如果没有,则对比UICamera的Canvas
        /// </summary>
        public static Transform GetTopCanvas()
        {
            Canvas[] canvases = GameObject.FindObjectsOfType<Canvas>();
            List<Canvas> overlayCanvases = new List<Canvas>();
            List<Canvas> uiCameraCanvases = new List<Canvas>();
            for (int i = 0; i < canvases.Length; i++)
            {
                Canvas _canvas = canvases[i];
                if (_canvas.renderMode == RenderMode.ScreenSpaceOverlay)
                {
                    overlayCanvases.Add(_canvas);
                }
                else if (_canvas.renderMode == RenderMode.ScreenSpaceCamera)
                {
                    uiCameraCanvases.Add(_canvas);
                }
            }
            Canvas mCanvas = null;
            for (int i = 0; i < overlayCanvases.Count; i++)
            {
                Canvas _canvas = overlayCanvases[i];
                if (!mCanvas)
                {
                    mCanvas = _canvas;
                }
                else
                {
                    if (_canvas.sortingOrder > mCanvas.sortingOrder)
                    {
                        mCanvas = _canvas;
                    }
                }
            }
            if (!mCanvas)
            {
                for (int i = 0; i < uiCameraCanvases.Count; i++)
                {
                    Canvas _canvas = uiCameraCanvases[i];
                    if (!mCanvas)
                    {
                        mCanvas = _canvas;
                    }
                    else
                    {
                        if (mCanvas.sortingOrder == _canvas.sortingOrder)
                        {
                            if (_canvas.planeDistance < mCanvas.planeDistance)
                            {
                                mCanvas = _canvas;
                            }
                        }
                        else
                        {
                            if (_canvas.sortingOrder > mCanvas.sortingOrder)
                            {
                                mCanvas = _canvas;
                            }
                        }
                    }
                }
            }
            if (mCanvas)
            {
                return mCanvas.transform;
            }
            return null;
        }

        /// <summary>
        /// 屏幕转换到UGUI坐标
        /// </summary>
        public static Vector2 ScreenToUGUIPoint(Vector3 screenPos, Canvas canvas)
        {
            Camera camera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, screenPos, camera, out Vector2 uiPos);
            return uiPos;
        }

        /// <summary>
        /// UGUI转换到屏幕坐标
        /// </summary>
        public static Vector3 UGUIToScreenPoint(RectTransform rectTransform)
        {
            Vector2 pos = rectTransform.anchoredPosition;
            Transform parent = rectTransform;
            Canvas canvas = parent.GetComponent<Canvas>();
            while (!canvas)
            {
                parent = parent.parent;
                canvas = parent.GetComponent<Canvas>();
                if (!canvas)
                {
                    pos += (parent as RectTransform).anchoredPosition;
                }
            }
            return UGUIToScreenPoint(canvas, pos);
        }

        /// <summary>
        /// UGUI转换到屏幕坐标
        /// </summary>
        public static Vector3 UGUIToScreenPoint(Canvas canvas, Vector2 uiPos)
        {
            Vector3 p;
            Vector2 screenUISize = ScreenUISize(canvas);
            p.x = Screen.width * (uiPos.x + screenUISize.x * 0.5f) / screenUISize.x;
            p.y = Screen.height * (uiPos.y + screenUISize.y * 0.5f) / screenUISize.y;
            p.z = 0;
            return p;
        }

        /// <summary>
        /// UGUI子物体锚点坐标转Canvas根坐标
        /// </summary>
        public static Vector2 LocalToRootPos(RectTransform target)
        {
            Vector2 pos = target.anchoredPosition;
            while (!target.parent.GetComponent<Canvas>())
            {
                target = target.parent as RectTransform;
                pos += new Vector2(target.anchoredPosition.x * target.localScale.x, target.anchoredPosition.y * target.localScale.y);
            }
            return pos;
        }

        /// <summary>
        /// 判断是否点击在UI上
        /// </summary>
        public static bool IsTouchOnAnyUI
        {
            get
            {
                if (Application.isEditor || Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.OSXPlayer)
                {
                    return EventSystem.current.IsPointerOverGameObject();
                }
                else
                {
                    return EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId);
                }
            }
        }

        /// <summary>
        /// Application.streamingAssets方法分平台处理，否则移动平台上可能无法下载数据(不带file:///)
        /// </summary>
        /// <returns></returns>
        public static string streamingAssetsPath
        {
            get
            {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
                return Application.dataPath + "/StreamingAssets";
#elif UNITY_ANDROID && !UNITY_EDITOR
                return Application.dataPath + "!/assets";
#elif UNITY_IOS && !UNITY_EDITOR
                return Application.dataPath + "/Raw";
#endif
            }
        }

        /// <summary>
        /// Application.streamingAssets方法分平台处理，否则移动平台上可能无法下载数据(自带file:///)
        /// </summary>
        /// <returns></returns>
        public static string streamingAssetsPathForWebRequest
        {
            get
            {
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
                return "file:///" + streamingAssetsPath;
#elif UNITY_ANDROID && !UNITY_EDITOR
                return "jar:file:///"+streamingAssetsPath;
#elif UNITY_IOS && !UNITY_EDITOR
                return "file:///"+streamingAssetsPath;
#endif
            }
        }

        /// <summary>
        /// 检测当前网络可用性
        /// </summary>
        public static bool IsNetWorkOK
        {
            get
            {
                return Application.internetReachability != NetworkReachability.NotReachable;
            }
        }

        /// <summary>
        /// 获取摄影机某距离处的视口四点位置
        /// </summary>
        public Vector3[] GetCameraCorners(Camera camera, float distance)
        {
            Vector3[] corners = new Vector3[4];
            float halfFOV = (camera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
            float aspect = camera.aspect;

            float height = distance * Mathf.Tan(halfFOV);
            float width = height * aspect;

            Transform tx = camera.transform;
            // UpperLeft
            corners[0] = tx.position - (tx.right * width);
            corners[0] += tx.up * height;
            corners[0] += tx.forward * distance;

            // UpperRight
            corners[1] = tx.position + (tx.right * width);
            corners[1] += tx.up * height;
            corners[1] += tx.forward * distance;

            // LowerLeft
            corners[2] = tx.position - (tx.right * width);
            corners[2] -= tx.up * height;
            corners[2] += tx.forward * distance;

            // LowerRight
            corners[3] = tx.position + (tx.right * width);
            corners[3] -= tx.up * height;
            corners[3] += tx.forward * distance;

            return corners;
        }

        /// <summary>
        /// 判断是否是带BOM的UTF8格式
        /// </summary>
        public static bool IsBOMUTF8(byte[] data)
        {
            int charByteCounter = 1;
            byte curByte;
            for (int i = 0; i < data.Length; i++)
            {
                curByte = data[i];
                if (charByteCounter == 1)
                {
                    if (curByte >= 0x80)
                    {
                        while (((curByte <<= 1) & 0x80) != 0)
                        {
                            charByteCounter++;
                        }
                        if (charByteCounter == 1 || charByteCounter > 6)
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    if ((curByte & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    charByteCounter--;
                }
            }
            return true;
        }

        /// <summary>
        /// 16进制颜色值转Color
        /// </summary>
        public static Color Color(string color, float alpha = 1)
        {
            Color _color;
            ColorUtility.TryParseHtmlString(color, out _color);
            return new Color(_color.r, _color.g, _color.b, alpha);
        }

        /// <summary>
        /// 段落文本空格不自动换行
        /// </summary>
        public static string TextSurportSpace(string text)
        {
            return text.Replace(" ", "\u00A0\u00A0");
        }

        /// <summary>
        /// 判断字符串中是否包含汉字
        /// </summary>
        public static bool IsIncludeChinese(string text)
        {
            return Regex.IsMatch(text, @"[\u4e00-\u9fa5]");
        }

        /// <summary>
        /// 射线检测碰撞到的所有UI
        /// </summary>
        public static GameObject[] RaycastAllUI(Vector3 screenPos)
        {
            EventSystem eventSystem = FindObjectOfType<EventSystem>();
            PointerEventData eventData = new PointerEventData(eventSystem);
            eventData.pressPosition = screenPos;
            eventData.position = screenPos;
            List<RaycastResult> list = new List<RaycastResult>();
            eventSystem.RaycastAll(eventData, list);
            GameObject[] games = new GameObject[list.Count];
            for (int i = 0; i < list.Count; i++)
            {
                games[i] = list[i].gameObject;
            }
            return games;
        }

        /// <summary>
        /// 自动创建目录的File.WriteAllBytes()方法
        /// </summary>
        public static void WriteAllBytes(string path, byte[] bytes)
        {
            if (bytes == null)
            {
                Debug.LogError("bytes为null");
                return;
            }
            if (Directory.Exists(path))
            {
                Debug.LogError($"path是一个已存在的文件夹路径:{path}");
                return;
            }
            string folderPath = Path.GetDirectoryName(path);
            if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
            File.WriteAllBytes(path, bytes);
        }

        /// <summary>
        /// 自动创建目录的File.WriteAllText()方法
        /// </summary>
        public static void WriteAllText(string path, string content)
        {
            if (content == null)
            {
                Debug.LogError("content为null");
                return;
            }
            if (content.Length == 0)
            {
                Debug.LogError("content为空字符串");
                return;
            }
            string folderPath = Path.GetDirectoryName(path);
            if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
            File.WriteAllText(path, content);
        }
    }
}